package com.ksyun.alert.service.impl;

import com.ksyun.alert.biz.bo.immediate.ImmediateCalculateBO;
import com.ksyun.alert.customException.SkyAlertException;
import com.ksyun.alert.dto.MetricDTO;
import com.ksyun.alert.entity.AlertMetricsDO;
import com.ksyun.alert.entity.AlertRecordsDO;
import com.ksyun.alert.entity.AlertRulesDO;
import com.ksyun.alert.service.AlertMetricsService;
import com.ksyun.alert.service.AlertRecordsService;
import com.ksyun.alert.service.CalculateImmediateService;
import com.ksyun.alert.utils.QLExpressUtil;
import com.ksyun.alert.utils.RequestIpUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 实时计算业务层接口实现
 * @author 蓝
 */
@Service
public class CalculateImmediateServiceImpl implements CalculateImmediateService {

    @Resource
    private AlertMetricsService alertMetricsService;

    @Resource
    private AlertRecordsService alertRecordsService;

    /**
     * 解析规则和参数列表
     * @param givenMetricsList 参数列表
     * @param immediateRulesList 规则列表
     */
    @Override
    public ImmediateCalculateBO doResolveNow(List<MetricDTO> givenMetricsList, List<AlertRulesDO> immediateRulesList) {
        List<String> neededMetricsList = Arrays.asList(immediateRulesList.stream()
                                                                        .map(AlertRulesDO::getMetric)
                                                                        .toArray(String[]::new));
        Map<String, Float> paramsMap = new HashMap<>();
        ImmediateCalculateBO immediateCalculateBO = new ImmediateCalculateBO();
        // 获取时间戳 和 主机名
        immediateCalculateBO.setTimestamp(givenMetricsList.get(0).getTimestamp());
        immediateCalculateBO.setHostName(givenMetricsList.get(0).getTags().get("hostname"));

        for (MetricDTO metricDTO : givenMetricsList) {
            if(neededMetricsList.contains(metricDTO.getMetric())){
                paramsMap.putIfAbsent(metricDTO.getMetric(), metricDTO.getValue());
            }
        }
        immediateCalculateBO.setParamsMap(paramsMap);
        return immediateCalculateBO;
    }

    /**
     * 执行即时计算
     * @param immediateCalculateBO 实时计算业务对象
     * @param alertRulesDO 告警规则表实体类
     */
    @Override
    @Transactional
    public void doCalculateNow(ImmediateCalculateBO immediateCalculateBO, AlertRulesDO alertRulesDO)  {
        Object result = null;
        Boolean isAlerted = null;
        try {
            result = QLExpressUtil.doCalculate(alertRulesDO.getExpression(), immediateCalculateBO.getParamsMap());
            isAlerted = QLExpressUtil.doCalComparison(result, alertRulesDO.getComparison(), alertRulesDO.getThreshold());
        } catch (Exception e) {
            throw new SkyAlertException(e.getMessage());
        }
        if(isAlerted){
            AlertRecordsDO alertRecordsDO = AlertRecordsDO.builder()
                                                        .alertMessage(alertRulesDO.getDescription())
                                                        .timestamp(immediateCalculateBO.getTimestamp())
                                                        .hostIp(RequestIpUtil.getRequestIp())
                                                        .ruleId(alertRulesDO.getId())
                                                        .severity(alertRulesDO.getSeverity())
                                                        .hostName(immediateCalculateBO.getHostName())
                                                        .build();
            alertRecordsService.getBaseMapper().insert(alertRecordsDO);
            AlertMetricsDO alertMetricsDO = AlertMetricsDO.builder()
                                                        .value(immediateCalculateBO.getParamsMap().get(alertRulesDO.getMetric()))
                                                        .recordId(alertRecordsDO.getId())
                                                        .metricName(alertRulesDO.getMetric())
                                                        .build();
            alertMetricsService.getBaseMapper().insert(alertMetricsDO);
        }
    }

}
